import { ref, reactive } from 'vue'
import { Service, injectable, mutex } from './service'
import NetService from './net.service'

declare type Permission = {
  id: string,
  name: string,
  code: string,
  pid: string,
  pcode: string,
  pname: string
}

declare type Role = {
  id: string,
  name: string,
  permissions: string[]
}

declare type User = {
  id: string,
  username: string,
  roleName: string,
  describe: string
}

@injectable
export default class UserService extends Service {
  /** 当前登录用户信息 */
  public user = reactive({
    describe: '',
    id: '',
    role: '',
    roleName: '',
    username: '',
    permissions: [] as string[]
  })

  public users = ref([] as User[])
  /** 所有权限 */
  permissions = ref([] as Permission[])
  roles = ref([] as Role[])

  /** 个人权限 */
  public rolesPermissions = ref(['get'])
  private netService = new NetService()

  /** 蒙层展示 */
  public showUserCenter = ref(false)
  /** 头像展示 */
  public showAvator = ref(false)
  /** 展示侧边导航栏 */
  public loginHideHeader = ref(false)
  public userInfo = reactive({
    describe: '',
    id: '',
    password: '',
    role: '',
    roleName: '',
    username: ''
  })

  public username = ''

  constructor () {
    super()
    try {
      this.username = localStorage.getItem('username') || ''
    } catch {
      //
    }
  }

  /** 新增用户 */
  async addUser (params: {
    id: number;
    username: string;
    password: string;
    describe: string;
    role: string;
  }) {
    const res = await this.netService.post('/accounts/insert', params)
    if (res?.success) {
      this.getUsers(true)
    }
    return res
  }

  /** 编辑用户 */
  async editUser (params: {
    id: number;
    describe: string;
    role: string
  }) {
    const res = await this.netService.post('/accounts/update', params)
    if (res?.success) {
      this.getUsers(true)
    }
    return res
  }

  /** 删除用户 */
  async deleteUser (params: { id: number }) {
    const res = await this.netService.post('/accounts/delete', params, 'posturl')
    if (res?.success) {
      this.getUsers(true)
    }
    return res
  }

  @mutex
  async getUsers (force = false) {
    if (!force && this.users.value.length > 0) {
      return
    }
    const res = await this.netService.get('/accounts/list', {})
    if (res?.success) {
      this.users.value = (res.data as Any[]).map(v => {
        return {
          id: v.id,
          username: v.username,
          role: v.role,
          roleName: v.roleName,
          describe: v.describe
        }
      })
    }
  }

  async getOnlyId () {
    return await this.netService.get('/onlyid')
  }

  /** 新增角色 */
  async addRole (params: {
    id: number;
    name: string;
    permissionsIds: string
  }) {
    const res = await this.netService.post('/roles/insert', params)
    if (res?.success) {
      this.getRoles(true)
    }
    return res
  }

  /** 编辑角色 */
  async editRole (params: {
    id: number;
    name: string;
    permissionsIds: number[]
  }) {
    const res = await this.netService.post('/roles/update', params)
    if (res?.success) {
      this.getRoles(true)
    }
    return res
  }

  /** 删除角色 */
  async deleteRole (params: { id: number }) {
    const res = await this.netService.post('/roles/delete', params, 'posturl')
    if (res?.success) {
      this.getRoles(true)
    }
    return res
  }

  @mutex
  async getRoles (force = false) {
    if (!force && this.roles.value.length > 0) {
      return
    }
    const res = await this.netService.get('/roles/list', {})
    if (res?.success) {
      this.roles.value = (res.data as Any[]).map(v => {
        return {
          id: v.id,
          name: v.name,
          permissions: v.permissions,
          permissionsNames: v.permissionsNames,
          perIds: v.perIds
        }
      })
    }
  }

  /** 新增权限 */
  async addPer (params: {
    id: number;
    name: string
  }) {
    const res = await this.netService.post('/permissions/insert', params)
    if (res?.success) {
      this.getPers(true)
    }
    return res
  }

  /** 编辑权限 */
  async editPer (params: {
    id: number;
    name: string
  }) {
    const res = await this.netService.post('/permissions/update', params)
    if (res?.success) {
      this.getPers(true)
    }
    return res
  }

  /** 删除权限 */
  async deletePer (params: { id: number }) {
    const res = await this.netService.post('/permissions/delete', params, 'posturl')
    if (res?.success) {
      this.getPers(true)
    }
    return res
  }

  /** 获取权限 */
  @mutex
  async getPers (force = false) {
    if (!force && this.permissions.value.length > 0) {
      return
    }
    const loop = (per: Permission, chain: string): string => {
      if (!per) {
        return chain
      }
      if (!per.pcode) {
        return `${per.code}${chain ? ('.' + chain) : ''}`
      } else {
        return loop(this.permissions.value.find(v => v.code === per.pcode)!, `${per.code}${chain ? ('.' + chain) : ''}`)
      }
    }
    const res = await this.netService.get('/permissions/list', {})
    if (res?.success) {
      this.permissions.value = res.data as Any[]
      this.permissions.value = this.permissions.value.map(v => {
        return {
          ...v,
          codes: loop(v, '')
        }
      })
    }
  }

  /** 获取权限树 */
  async perTree () {
    const res = await this.netService.get('/permissions/tree')
    if (res?.success) {
      return res
    }
  }

  // 登录
  @mutex
  async login (params: {
    username: string;
    password: string;
  }) {
    this.username = params.username
    return await this.netService.post('/login', params)
  }

  // 密码加密
  async signPassword (pwd: string) {
    const data = new TextEncoder().encode(pwd)
    const sign = await crypto.subtle.digest('SHA-256', data)
    return new Uint8Array(sign).map(v => v.toString(16) as Any).join('')
  }

  /** 个人信息 */
  @mutex
  async getAccountInf (params?: { username: string }) {
    if (this.user.id) {
      return
    }
    const res = await this.netService.get('/accounts/get', params)
    if (!res?.success || !res?.data) {
      return null
    }
    this.user.describe = res.data.describe
    this.user.username = res.data.username
    this.user.id = res.data.id
    this.user.role = res.data.role
    if (res.data.role === null) {
      return null
    }
    await this.getRoles()
    await this.getPers()
    this.user.roleName = this.roles.value.find(v => v.id === res.data.role)?.name || '未知'
    this.user.permissions = this.roles.value.find(v => v.id === res.data.role)?.permissions || []
    this.user.permissions = this.user.permissions.filter(v => this.user.permissions.findIndex(vv => vv.startsWith(`${v}.`)) < 0)
    return true
  }

  // 修改密码
  async changePwd (params: {
    username: string, // 账号,not null
    oldPwd: string, // 旧密码,not null
    newPwd: string // 新密码,not null
  }) {
    return await this.netService.post('/accounts/updatepwd', params)
  }

  // 退出登录
  async logOut () {
    localStorage.removeItem('username')
    return await this.netService.post('/logout')
  }

  public checkPermissions (permissions: string[]): boolean {
    if (!permissions || permissions.length < 1) {
      return true
    }
    for (const permission of permissions) {
      if (!permission) {
        continue
      }
      if (!this.hasPermission(permission)) {
        return false
      }
    }
    return true
  }

  private hasPermission (code: string): boolean {
    if (!code) {
      return true
    }
    if (!code.includes('.') || code.startsWith('.') || code.endsWith('.')) {
      return false
    }
    for (const per of this.user.permissions) {
      if (per === code) {
        return true
      }
      if (per.includes('*') && code.startsWith(per.substring(0, per.indexOf('*')))) {
        return true
      }
    }
    return false
  }
}
